#include "stdafx.h"
#include "terrain.h"
#include "gamemanager.h"
#include "TextureRender2.h"
#include "TextureRender.h"
#include "Scene.h"
#include "MapManager.h"

const uint8 defaultTerrain = 144;
CTerrain::CTerrain()
{
    m_grids = NULL;
    m_sizex = 0;
    m_sizey = 0;
    m_terrainAlphaTexID = CD3DManager::Instance().AddTexture(L"data\\terrainalpha.tga");
    m_terrainTexId = CD3DManager::Instance().AddTexture(L"data\\terrainsheet.tga");
}

CTerrain::~CTerrain()
{
    SAFE_DELETE_ARRAY( m_grids );
}

bool CTerrain::SetDimension( uint32 sizex, uint32 sizey, bool keepOld )
{
    if( sizex == m_sizex && sizey == m_sizey )
        return true;
    GridDatas newdata = new SGridData[sizex*sizey];
    memset( newdata, 0, sizex*sizey*sizeof(SGridData));
    if( keepOld )
    {
        uint32 cpdatalen = min(sizex*sizey, m_sizex*m_sizey);
        memcpy( newdata, m_grids, cpdatalen );
    }
    SAFE_DELETE( m_grids );
    m_sizex = sizex;
    m_sizey = sizey;
    m_grids = newdata;
    RandomTerrain();
    return true;
}

void CTerrain::SetGridTerrain( uint32 x, uint32 y, SGridData &data )
{
    SGridData *g = GetGrid( x, y );
    if( g )
    {
        g->gridType = data.gridType;
    }
}

void CTerrain::Render()
{
    static CTextureRender2 tbase;
    static CTextureRender2 ttile;

    tbase.SetTextureID( m_terrainTexId );
    tbase.SetTextureID2( m_terrainAlphaTexID );
    tbase.SetRenderType( eRender_Tex1All_Tex2Alpha );
    tbase.SetPriority( eLayer_Terrain_Base );
    tbase.ClearVertexData();

    ttile.SetTextureID( m_terrainTexId );
    ttile.SetTextureID2( m_terrainAlphaTexID );
    ttile.SetRenderType( eRender_Tex1All_Tex2Alpha );
    ttile.SetPriority( eLayer_Terrain );
    ttile.ClearVertexData();
    
    int w = gc.gridsize;
    int mapx = gc.mapregion.x1;
    int mapy = gc.mapregion.y1;
    float d = 1.0f/16.0f;
    for( uint32 i=0;i<m_sizex;i++ )
    {
        for( uint32 j=0;j<m_sizey;j++ )
        {
            IRect rect( mapx+i*w, mapy+j*w, mapx+i*w+w, mapy+j*w+w );
            CMapManager::Instance().ConvertToScaledCoord( rect );
            if( !IntersectRect( rect, gc.screenrect ) )
                continue;
            float minx = (float)(rect.x1 - gc.screenrect.x1);
            float miny = (float)(rect.y1 - gc.screenrect.y1);
            float maxx = (float)(minx + rect.Width() - 1);
            float maxy = (float)(miny + rect.Height() - 1);
            
            float texoffset = 1.0f/2048.0f;

            int u=defaultTerrain%16;
            int v=defaultTerrain/16;
            float m_u1=d*u+texoffset, m_v1=d*v+texoffset, m_u2=d+d*u, m_v2 = d+d*v;

            int alphaindex = 0;
            if( j == 0 )
                alphaindex |= (1<<3);
            if( j == m_sizey - 1 )
                alphaindex |= (1<<1);
            if( i == 0 )
                alphaindex |= (1<<2);
            if( i == m_sizex - 1 )
                alphaindex |= 0x0001;
            
            float offset = 1.0f/256.0f;
            float m_u1_2=0.0f, m_v1_2=0.0f, m_u2_2= 63.0f/255.0f, m_v2_2 = 63.0f/255.0f;
            if( alphaindex != 0 )
            {
                int u = alphaindex%4, v = alphaindex/4;
                m_u1_2 = float(u*64)/255.0f;
                m_v1_2 = float(v*64)/255.0f;
                m_u2_2 = float(u*64-1+64)/255.0f;
                m_v2_2 = float(v*64-1+64)/255.0f;
            }
            
            Vertex_RHW_TEX2 ver[]=
            {
                {minx,miny,0.0f,1.0f,m_u1,m_v1,m_u1_2,m_v1_2},
                {maxx,miny,0.0f,1.0f,m_u2,m_v1,m_u2_2,m_v1_2},
                {maxx,maxy,0.0f,1.0f,m_u2,m_v2,m_u2_2,m_v2_2},

                {minx,miny,0.0f,1.0f,m_u1,m_v1,m_u1_2,m_v1_2},
                {maxx,maxy,0.0f,1.0f,m_u2,m_v2,m_u2_2,m_v2_2},
                {minx,maxy,0.0f,1.0f,m_u1,m_v2,m_u1_2,m_v2_2},
            };
            tbase.AddVertexData( ver, 6 );


            SGridData *grid = GetGrid(i,j);
            if( grid->gridType == defaultTerrain )
                continue;
            alphaindex = 0;
            SGridData *left = GetGrid(i-1,j);
            SGridData *right = GetGrid(i+1,j);
            SGridData *up = GetGrid(i,j-1);
            SGridData *down = GetGrid(i,j+1);
            if( !left || left->gridType!=grid->gridType )
                alphaindex |= (1<<2);
            if( !right || right->gridType!=grid->gridType )
                alphaindex |= (1);
            if( !up || up->gridType!=grid->gridType )
                alphaindex |= (1<<3);
            if( !down || down->gridType!=grid->gridType )
                alphaindex |= (1<<1);

            m_u1_2=0.0f, m_v1_2=0.0f, m_u2_2= 63.0f/255.0f, m_v2_2 = 63.0f/255.0f;
            if( alphaindex != 0 )
            {
                int u = alphaindex%4, v = alphaindex/4;
                m_u1_2 = float(u*64)/255.0f;
                m_v1_2 = float(v*64)/255.0f;
                m_u2_2 = float(u*64-1+64)/255.0f;
                m_v2_2 = float(v*64-1+64)/255.0f;
            }
            //m_u1_2=0.0f;
            //m_v1_2=0.0f;
            //m_u2_2= 0.25f;
            //m_v2_2 = 0.25f;
            //if( alphaindex != 0 )
            //{
            //    int u = alphaindex%4, v = alphaindex/4;
            //    m_u1_2 = u*0.25f+offset;
            //    m_v1_2 = v*0.25f+offset;
            //    m_u2_2 = 0.25f+u*0.25f;
            //    m_v2_2 = 0.25f+v*0.25f;
            //}
            //float m_u1=0.0f, m_v1=0.0f, m_u2=128.0f/2048.0f, m_v2 = 128.0f/2048.0f;
            //float d = 1.0f/16.0f;
            u=grid->gridType%16;
            v=grid->gridType/16;
            m_u1=d*u+texoffset;
            m_v1=d*v+texoffset;
            m_u2=d+d*u;
            m_v2 = d+d*v;
            Vertex_RHW_TEX2 ver2[]=
            {
                {minx,miny,0.0f,1.0f,m_u1,m_v1,m_u1_2,m_v1_2},
                {maxx,miny,0.0f,1.0f,m_u2,m_v1,m_u2_2,m_v1_2},
                {maxx,maxy,0.0f,1.0f,m_u2,m_v2,m_u2_2,m_v2_2},

                {minx,miny,0.0f,1.0f,m_u1,m_v1,m_u1_2,m_v1_2},
                {maxx,maxy,0.0f,1.0f,m_u2,m_v2,m_u2_2,m_v2_2},
                {minx,maxy,0.0f,1.0f,m_u1,m_v2,m_u1_2,m_v2_2},
            };
            ttile.AddVertexData( ver2, 6 );
        }
    }
    CScene::Instance().AddRenderObject( &tbase );
    CScene::Instance().AddRenderObject( &ttile );
}

void CTerrain::RandomTerrain()
{
    for( uint32 i=0; i<m_sizex; i++ )
    {
        for( uint32 j=0; j<m_sizey; j++ )
        {
            if( happen(0.0f) )
                GetGrid(i,j)->gridType = 14+random(3);
            else
                GetGrid(i,j)->gridType = defaultTerrain;
        }
    }
}

SGridData * CTerrain::GetGrid( uint32 x, uint32 y )
{
    if( !ValidCoord( x, y ) )
        return NULL;
    return &m_grids[y*m_sizex + x];
}

bool CTerrain::ValidCoord( uint32 x, uint32 y )
{
    return x < m_sizex && y < m_sizey;
}

void CTerrain::SaveTerrainTileToFile( LPCTSTR dir )
{
    TCHAR currentpath[1024] = {0};
    ::GetCurrentDirectory( MAX_PATH, currentpath );
    _tcscat( currentpath, dir );
    BOOL result = ::CreateDirectory( currentpath,NULL );
    
    int icontexid = CD3DManager::Instance().AddTexture( L"data\\terrainsheet_small.tga" );
    if( icontexid == -1 )
        return;
    TextureInfo *info = CD3DManager::Instance().GetTextureInfo(icontexid);
    CHECK_PTR_VOID( info );

    D3DLOCKED_RECT lockedrect;
    HRESULT hr = info->texture->LockRect( 0, &lockedrect, 0, 0 );
    if( hr != S_OK )
        return;
    D3DSURFACE_DESC desc;
    info->texture->GetLevelDesc( 0, &desc );
    
    const int tilesize = 32;
    for( uint32 i=0; i<16; i++ )
    {
        for( uint32 j=0; j<16; j++ )
        {
            tstringstream filepath;
            filepath<<currentpath<<L"icon_"<<i<<'_'<<j<<".bmp"<<'\0';
            WIN32_FIND_DATA finddata;
            if( FindFirstFile( filepath.str().c_str(), &finddata) != INVALID_HANDLE_VALUE )
                continue;
            CTexture tex;
            RECT rect ={i*tilesize, j*tilesize, i*tilesize + tilesize - 1, j*tilesize + tilesize - 1};
            tex.LoadTexture( desc.Width, desc.Height, rect, (const char *)lockedrect.pBits ); 
            tex.SaveTextureToFile( filepath.str().c_str(), D3DXIFF_BMP );
        }
    }
    info->texture->UnlockRect( 0 );
}

void CTerrain::Save()
{
    const char *path = "data\\terrain.dat";
    std::ofstream f;
    f.open( path, std::ios_base::out|std::ios_base::binary );
    if( f.is_open() )
    {
        f.write( (const char *)m_grids, m_sizex*m_sizey*sizeof(SGridData) );
    }
    f.close();
}

void CTerrain::Load()
{
    const char *path = "data\\terrain.dat";
    std::ifstream f;
    f.open( path, std::ios_base::in|std::ios_base::binary );
    if( f.is_open() )
    {
        f.seekg( 0, std::ios_base::end );
        uint32 fsize = f.tellg();
        f.seekg( 0, std::ios_base::beg );
        int tilecount = fsize/sizeof(SGridData);
        if( tilecount == m_sizex*m_sizey )
        {
            f.read( (char*)m_grids, fsize );
        }
        f.close();
    }
}
